package moltencore.network.serverlobby;

import org.apache.log4j.Logger;

import java.net.SocketException;
import java.net.DatagramPacket;
import java.net.InetSocketAddress;

import moltencore.network.protocol.*;
import moltencore.network.serverlobby.StrategyFactory;
import spark.network.Util;
import spark.network.Demon;
import spark.network.ActiveClientList;
import spark.network.ServerSender;
import spark.network.protocol.*;
import moltencore.player.PlayerList;
import moltencore.player.Player;
import moltencore.config.Config;

/**
 * Demon handling the player list and creation of games.
 */
public class LobbyDemon extends Demon implements Runnable {
	private static Logger logger = Logger.getLogger(LobbyDemon.class);

	private LobbyDemonHandler handler;
	private StrategyFactory strategyFactory;

	public LobbyDemon(ActiveClientList clients, ServerSender sender,
	                  PlayerList<Player> playerList) throws SocketException {
		super(Config.getInstance().getQueryUdpPort());
		moltencore.network.serverlobby.GameList gameList = new GameList();
		handler = new LobbyDemonHandler(clients, sender);
		setTimeAdjuster(handler);
		playerList.addAuthorizationListener(clients);
		strategyFactory = new StrategyFactory(playerList, gameList);
	}

	@Override
	protected void processPacket(DatagramPacket packet, long receiveTime) {
		byte[] packetData = packet.getData();
		InetSocketAddress source = Util.extractInetSocketAddress(packet);
		switch(Base.getType(packetData)) {
			case Acknowledgement.TYPE:
				logger.debug("Received: Acknowledgement from " + source);
				handler.handle(Acknowledgement.create(packetData, receiveTime), source);
				break;
			case PreLoginResponseAck.TYPE:
				logger.debug("Received: PreLoginResponseAck from " + source);
				handler.handle(PreLoginResponseAck.create(packetData, receiveTime), source);
				break;
			case ClockSyncRes.TYPE:
				logger.debug("Received: ClockSyncRes from " + source);
				handler.handle(ClockSyncRes.create(packetData, receiveTime), source);
				break;
			case KeepAlive.TYPE:
				logger.debug("Received: KeepAlive from " + source);
				logger.warn("No handling routine for keep alive");
				break;
			case PreLogin.TYPE:
				logger.debug("Received: PreLogin from " + source);
				handler.handle(PreLogin.create(packetData, receiveTime), source);
				break;
			case Login.TYPE:
				logger.debug("Received: Login from " + source);
				handler.handle(Login.create(packetData, receiveTime), source, strategyFactory.getLoginStrategy());
				break;
			case Logout.TYPE:
				logger.debug("Received: Logout from " + source);
				handler.handle(Logout.create(packetData, receiveTime), source, strategyFactory.getLogoutStrategy());
				break;
			case CreateGame.TYPE:
				logger.debug("Received: Creategame from " + source);
				handler.handle(CreateGame.create(packetData, receiveTime), source, strategyFactory.getCreateGameStrategy());
				break;
			case GameListRequest.TYPE:
				logger.debug("Received: GameListRequest from " + source);
				handler.handle(GameListRequest.create(packetData, receiveTime), source, strategyFactory.getGameListRequestStrategy());
				break;
			default:
				//TODO : when done with programming the protocol remove this warn message
				//unknown protocol type received, ignore it
				logger.warn("Unknown protocol type received " + Integer.toHexString(Base.getType(packet.getData())) + ". Forgot to handle this protocol type?");
				break;
		}
	}
}
